const RENDER_TO_DOM = Symbol("render to dom");

class ElementWrapper {
  constructor(type) {
    this.root = document.createElement(type);
  }
  
  setAttribute(key, value) {
    if (key.match(/^on([\s\S]+)$/)) {
      this.root.addEventListener(RegExp.$1.replace(/^[\s\S]+$/, c => c.toLowerCase()), value);
    } else if (key === "className") {
      this.root.setAttribute("class", value);
    } else {
      this.root.setAttribute(key, value);
    }
  }
  
  /**
   * appendChild 不能适应更新，需要调用 RENDER_TO_DOM 来实现更新数据重新渲染
   * 这里做调整
   *
   * 本来是父组件主动挂载子组件 this.root.appendChild(child.root);
   * 现在是通过调用子组件的 RENDER_TO_DOM 方法来将子组件挂载到父组件上
   * */
  appendChild(component) {
    let range = document.createRange();
    range.setStart(this.root, this.root.childNodes.length);
    range.setEnd(this.root, this.root.childNodes.length);
    component[RENDER_TO_DOM](range);
    // this.root.appendChild(child.root);
  }
  
  [RENDER_TO_DOM](range) {
    range.deleteContents();
    range.insertNode(this.root);
  }
}

class TextWrapper {
  constructor(content) {
    this.root = document.createTextNode(content);
  }
  
  [RENDER_TO_DOM](range) {
    range.deleteContents();
    range.insertNode(this.root);
  }
}

class Component {
  constructor() {
    this.props = {};
    this.children = [];
    this._root = null;
    this._range = null;
    this.state = null;
  }
  
  setAttribute(key, value) {
    this.props[key] = value;
  }
  
  appendChild(component) {
    this.children.push(component);
  }
  
  // 当数据变化重新渲染的时候，就不能append了，这个时候需要一个可以将组件渲染到指定位置的函数，
  // dom 中可以指定位置的 api 是 Range
  [RENDER_TO_DOM](range) {
    this._range = range;
    this.render()[RENDER_TO_DOM](range);
  }
  
  // 重新绘制
  rerender() {
    this._range.deleteContents();
    this[RENDER_TO_DOM](this._range);
  }
  
  setState(newState) {
    if (newState !== null && typeof newState === "object") {
      if (this.state === null) {
        this.state = newState;
      } else {
        let merge = (oldState, newState) => {
          for (let key in newState) {
            if (oldState[key] !== null && typeof oldState[key] === "object") {
              merge(oldState[key], newState[key]);
            } else {
              oldState[key] = newState[key];
            }
          }
        };
        merge(this.state, newState);
      }
      this.rerender();
    }
  }
  
  // get root() {
  //   if (!this._root) {
  //     // 自动形成一个递归调用
  //     this._root = this.render().root;
  //   }
  //   return this._root;
  // }
}

function createElement(type, attributes, ...children) {
  let e;
  if (typeof type === "string") {
    e = new ElementWrapper(type);
  } else {
    e = new type;
  }
  
  for (let p in attributes) {
    e.setAttribute(p, attributes[p]);
  }
  
  const insertChildren = (children) => {
    for (let child of children) {
      if (child === null || child === undefined || child === true || child === false) {
        continue;
      }
      if (typeof child === "string") {
        child = new TextWrapper(child);
      }
      if (Array.isArray(child)) {
        insertChildren(child);
      } else {
        e.appendChild(child);
      }
    }
  };
  insertChildren(children);
  return e;
}

const render = (component, parentElement) => {
  let range = document.createRange();
  range.setStart(parentElement, 0);
  // 这里使用 childNodes 将文本节点，注释节点，元素节点全部删掉
  range.setEnd(parentElement, parentElement.childNodes.length);
  range.deleteContents();
  component[RENDER_TO_DOM](range);
  // parentElement.appendChild(component.root);
  
};
export {
  createElement, Component, render,
};
